#include "prochan.h"
#include "MPX_SUPT.H"
#include "comhan.h"
#include <dos.h>


/* Global variables */
extern pcbBase ready;
extern pcbBase blocked;

/* Global Variables */
char *inBuff; // input buffer
char *outBuff; // output buffer
int buffSize = 512; // size of buffers
int (*commands[])(char *, char *)={exitProgram, listDir, displayVersion,
displayDate, help, setDate, suspendPCB, setPriority, resumePCB, print, r4loader, T800}; // function pointer array for commands

/**
 * \brief Main loop for entering commands.
 * Cycles through taking input from the user.
 */
void inputLoop(){
	int returnCode;
	clrscr();
	output("Welcome to Dark Side Coders operating system\n", 1);
	while (TRUE){
		output("mpx:>", 1);
		returnCode = commandParser(getInput());
		if (returnCode!=1){
			output("unknown command, type 'help' for list of commands\n", 1);
		}
	}
}

/** \brief Gets input from the command line, returns null pointer if there is an error.
 * @return string - the input from command line.
 */
char* getInput(){
	int i = 0;
	char *input;
	buffSize = 512;
	sys_req(READ, TERMINAL, inBuff, &buffSize);
	if (buffSize > 0){
		for(i = 0; i < buffSize; i++){ // removes new line character from input buffer
			if (inBuff[i] == '\n'){
				inBuff[i]= '\0' ;
			}
		}
		input = inBuff;
		while (input[0] == ' ' & input[0] != 0){ // removes spaces before input
			input=input+1;
		}
	}
	return input;

}

/** \brief outputs to the command line.
 * @param buff string - the information to be output
 */
int output(char *buff, int reset){
	static int counter = 0;
	int length = strlen(buff);
	if (reset){
		counter = 0;
	}
	if(length<=512){
		sys_req(WRITE, TERMINAL, buff, &length);
		counter += 1;
	}
	else {
		return ERR_SUP_INVPOS; // invalid string size
	}
	if (counter >= 40){
		length = 24;
		sys_req(WRITE, TERMINAL, "Press enter to continue.", &length);
		getInput();
		counter = 0;
	}
	return (1);
}

/** \brief initializes global variables.
 * @return int - returns 1 if completed successfully
 */
int initComHan(){
	pcb *temppcb;
	context *npc;
	 int i;
	inBuff=sys_alloc_mem(buffSize);
	outBuff=sys_alloc_mem(buffSize);
	for (i=0;i<buffSize;i++){
		inBuff[i]=0;
		outBuff[i]=0;
	}
	ready.first = NULL;
	ready.last = NULL;
	blocked.first = NULL;
	blocked.last = NULL;
	temppcb = setupPCB("Terminal", 127, SYSTEM, 1, 0, 8192);
	temppcb->state = READY;
	temppcb->stackTop = temppcb->stackTop - sizeof(context);
	npc = (context*) temppcb->stackTop;
	npc->IP = FP_OFF(&inputLoop);
	npc->CS = FP_SEG(&inputLoop);
	npc->FLAGS = 0x200;
	npc->DS = _DS;
	npc->ES = _ES;
	temppcb->state = READY;
	insertPCB(temppcb);
	loader("idle", (-128), 1024);
	return (OK);
}
/** \brief takes in command string and parses it into command and arguments.
 * Takes in a string and parses it into a command and arguments
 * it then compares the command against all possible commands
 * once the correct command is found it then calls the command
 * @param input string - the string to parse
 * @return int - returns 1 if command is found
 */
int commandParser(char *input){
	int i = 0, length = 0;
	char *command = NULL;
	char *arguments = NULL;
	char delim[]=" ";
	int rc = 0;
	length=strlen(input);
	rc = 0;
	if (length>0){
		length=strlen(input);
		arguments = input;
		while (arguments[0] != ' ' & arguments[0] != 0){ // increments arguments past the command
			arguments = arguments +1;
		}
		while (arguments[0] == ' ' & arguments[0] != 0){ // removes spaces before arguments
			arguments = arguments +1;
		}
		command = strtok(input, delim);
		/* test for valid command */
		for (i=0;i<sizeof(commands)/sizeof(commands[0]);i++){
			if (commands[i](command, arguments)==1){
				rc = 1;
				break;
			}
		}
	}
	return rc;
}

/**
 * \brief Exits the program.
 * Deallocates all allocated memory and exits the program.
 * @param command string - the command issued by the user
 * @param arguments string - the arguments issued by the user
 * @return int - returns 0 if this is not the correct command otherwise 1
 */
int exitProgram(char* command, char* arguments){
	char* exitAnswer;
	pcb *temp;
	if (strcmp(command, "exit")==0 & arguments[0]==0){
		output("Are you sure you want to exit?\n yes / no :>", 1);
		exitAnswer = getInput();
		if (strcmp(exitAnswer, "yes")==0){
			T1000(blocked.first);
			T1000(ready.first);
			ready.first = NULL;
			sys_free_mem(inBuff);
			sys_free_mem(outBuff);
			com_close();
			trm_close();
			sys_req(EXIT, NO_DEV, NULL, 0);
		}
		return 1;
	}
	return 0;
}


/**
 * \brief Lists all MPX files in the current directory.
 * @param command string - the command issued by the user
 * @param arguments string - the arguments issued by the user
 * @return int - returns 0 if this is not the correct command otherwise 1
 */
int listDir(char* command, char* arguments)
{
	 int dirErr, rc;
	 char path[150];
	if (strcmp(command, "ls") == 0 & arguments[0] == 0){
		output(arguments, 0);
		rc = 1;
		getcwd(path,150);
		dirErr = sys_open_dir(path);//open the directory
		if(dirErr == -110)
		{

			output("This is not a valid directory", 1);
		}
		else if(dirErr == -111)
		{
			output("The directory could not be opened", 1);
		}
		else
		{
			//dir now open, need to pull files within

			while(1)
			{

				 char fileName[50];
				 long fileSize = 0;
				//int sys_get_entry(char name_buf[], int buf_size, long *file_size_p);
				//-matically searches the open directory for the next .MPX file
				//that hasn't been retrieved
				dirErr = sys_get_entry(fileName,50,&fileSize);

				if(dirErr == -113)
				{
					break;
				}
				else if(dirErr == -112)
				{
					output("The directory could not be opened", 1);
					break;
				}
				else if(dirErr == -104)
				{
					output("The file could not be read", 1);
					break;
				}
				else if(dirErr== -114)
				{
					output("The file name is too long", 1);
					break;
				}
				else
				{
					sprintf(outBuff,"%s   %ld\n",fileName,fileSize);
					output(outBuff, 0);
				}
			}

			//Now that you are done reading everything and displaying it, it's time to close the directory
			sys_close_dir();
		}
	}
	else {
		rc = 0;
	}
	return rc;
}

/**
 * \brief Dispays the version number.
 * @param command string - the command issued by the user
 * @param arguments string - the arguments issued by the user
 * @return int - returns 0 if this is not the correct command otherwise 1
 */
int displayVersion(char* command, char* arguments){
	if (strcmp(command, "version")==0 & arguments[0]==0){
		output("Version: 2.1\n", 1);
		return 1;
	}
	return 0;
}//close displayVersion

/**
 * \brief Displays the current date.
 * @param command string - the command issued by the user
 * @param arguments string - the arguments issued by the user
 * @return int - returns 0 if this is not the correct command otherwise 1
 */
int displayDate(char* command, char* arguments){
	date_rec current_date;
	if (strcmp(command, "date")==0 & arguments[0]==0){
		char datebuff[30];
		//		current_date=sys_alloc_mem(sizeof(date_rec));
		sys_get_date(&current_date); // the * which was here is not needed, the function takes in a pointer not a value
		sprintf(datebuff, "Current date is: %d-%d-%d.\n", current_date.month, current_date.day, current_date.year);
		output(datebuff, 1);
		return 1;
	}
	return 0;
}//close displayDate

/**
 * \brief Displays the help dialouge.
 * Displays help for a single command or a brief description of all commands.
 * @param command string - the command issued by the user
 * @param arguments string - the arguments issued by the user
 * @return int - returns 0 if this is not the correct command otherwise 1
 */
int help(char* command, char* arguments){
	 char* arg=NULL;
	 int out, i;
	 FILE *helpFile;
	 char *buff;
	if (strcmp(command, "help")==0){
		buff = sys_alloc_mem(2);
		if (arguments[0]==0){
			strcpy(arg, "help.hlp");
		}
		else{
			strcat(arguments, ".hlp");
			arg = arguments;
		}
		helpFile = fopen(arg, "r");
		if (helpFile==NULL){
			output("Help file not found.\n", 1);
		}
		out = fgetc(helpFile);
		while(out!=EOF){
			buff[0]=out;
			buff[1]=0;
			output(buff, 1);
			out = fgetc(helpFile);
		}
		output("\n\n", 1);
		fclose(helpFile);
		return 1;
	}
	return 0;
}

/**
 * \brief Sets the date.
 * Sets the date to what the user inputs.
 * @param command string - the command issued by the user
 * @param arguments string - the arguments issued by the user
 * @return int - returns 0 if this is not the correct command otherwise 1
 */
int setDate(char *command, char *arguments){
	int validMonth=0, validDay=0, validYear=0, leapYearFlag=0, i;
	date_rec *setdate;
	char *month, *day, *year;
	if (strcmp(command, "setdate")==0){
		month = sys_alloc_mem(10);
		day = sys_alloc_mem(10);
		year = sys_alloc_mem(10);
		setdate = sys_alloc_mem(sizeof(date_rec));
		month = strtok(arguments, "-");
		day = strtok(NULL, "-");
		year = strtok(NULL, "-");

		for (i = 0; i < 10; i++){
			if ((month[i] < 48 || month[i] > 57) && month[i] != 0){
				output("Non number characters in month string.\n", 1);
				return 1;
			}
			if ((day[i] < 48 || day[i] > 57) && day[i] != 0){
				output("Non number characters in day string.\n", 1);
				return 1;
			}
			if ((year[i] < 48 || year[i] > 57) && year[i] != 0){
				output("Non number characters in year string.\n", 1);
				return 1;
			}
		}
		setdate -> month=atoi(month);
		setdate -> day=atoi(day);
		setdate -> year= atoi(year);

		//check for leap year
		if ((setdate -> year%4)==0 && (setdate -> year%400)!=0){
			leapYearFlag = 1;
		}//close if

		//Ensure month is valid
		if(setdate -> month <= 12 && setdate -> month >= 1){
			validMonth = 1;
		}//close if
		else{
			output("The month must be between 1-12 to be valid.\n", 1);
			validMonth = 0;
		}//close else

		//Ensure Day is valid
		if(setdate -> month == 11 || setdate -> month == 9 || setdate -> month == 6 || setdate -> month == 4){
			if(setdate -> day >= 1 && setdate -> day <= 30){
				validDay = 1;
			}
			else{
				output("The day needs to be between 1 and 30 for this month.\n", 1);
				validDay = 0;
			}//close else
		} //close if
		else if(setdate -> month >= 1 && setdate -> month <= 12 && setdate -> month != 2){
			if(setdate -> day >= 1 && setdate -> day <= 31){
				validDay = 1;
			}
			else{
				output("The day needs to be between 1 and 31 for this month.\n", 1);
				validDay = 0;
			}//close else

		}//close else if
		else if(setdate -> month == 2){
			if((setdate -> day >= 1 && setdate -> day <= 28) && leapYearFlag == 0){
				validDay = 1;
			}
			else if((setdate -> day >= 1 && setdate -> day <= 29) && leapYearFlag == 1){
				validDay = 1;
			}
			else{
				output("The day needs to be between 1-28, or 1-29 if a leap year)\n", 1);
				validDay = 0;
			}//close else
		}//close else if

		if(setdate -> year >= 1941 && setdate -> year <= 9999){
			validYear = 1;
		}//close if
		else{
			output("Either the year entered was too early to be a valid computer, or the date is too far in the future.\n", 1);
			validYear = 0;
		}//close else
		if(validMonth == 1 && validDay == 1 && validYear == 1){
			sys_set_date(setdate);
			sprintf(outBuff, "The date set is: %d-%d-%d\n\n", setdate->month, setdate->day, setdate->year);
			output(outBuff, 1);
		}//close if
	}
	else{
		return 0;
	}
	return 1;
}//close setDate

/** \brief This puts a PCB into the blocked queue and changes its status to blocked.
 * blockPCB takes a ready or suspended ready PCB and places it into the blocked queue
 * or suspended blocked queue respectively.  This cannot be called on a blocked or
 * suspended blocked PCB.
 * @param command string - the command issued by the user
 * @param arguments string - the arguments issued by the user
 * @return int - returns 0 if this is not the correct command otherwise 1
 */
int blockPCB(char *command, char *arguments)
{
	 pcb *currentPCB;
	if (strcmp(command, "block")==0){
		currentPCB = findPCB(arguments);

		if(currentPCB != NULL)
		{
			if(currentPCB->state == 3 || currentPCB->state == 5)
				output("This PCB is already blocked", 1);
			else if(currentPCB->state == 2)
			{
				removePCB(arguments);
				currentPCB->state = 3;
				insertPCB(currentPCB);
			}
			else
			{
				removePCB(arguments);
				currentPCB->state = 5;
				insertPCB(currentPCB);
			}
		}
		return (1);
	}
	else{
		return 0;
	}
}

/** \brief This puts a PCB into the ready queue and changes its status to ready.
 * unblockPCB takes a blocked or suspended blocked PCB and places it into the ready queue
 * or suspended ready queue respectively.  This cannot be called on a ready or
 * suspended ready PCB.
 * @param command string - the command issued by the user
 * @param arguments string - the arguments issued by the user
 * @return int - returns 0 if this is not the correct command otherwise 1
 */
int unblockPCB(char *command, char *arguments)
{
	 pcb *currentPCB;
	if (strcmp(command, "unblock")==0){
		currentPCB = findPCB(arguments);

		if(currentPCB != NULL)
		{
			if(currentPCB->state == 2 || currentPCB->state == 4)
				output("This PCB is already ready", 1);
			else if(currentPCB->state == 3)
			{
				removePCB(arguments);
				currentPCB->state = 2;
				insertPCB(currentPCB);
			}
			else
			{
				removePCB(arguments);
				currentPCB->state = 4;
				insertPCB(currentPCB);
			}
		}
		return (1);
	}
	else {
		return 0;
	}
}

/** \brief This changes the status of the PCB to suspended.
 * suspendPCB takes a ready or blocked PCB and changes its status to
 * suspended ready or suspended blocked respectively. This cannot be
 * called on a suspended ready or suspended blocked PCB.
 * @param command string - the command issued by the user
 * @param arguments string - the arguments issued by the user
 * @return int - returns 0 if this is not the correct command otherwise 1
 */
int suspendPCB(char *command, char *arguments)
{
	 pcb *currentPCB;
	if (strcmp(command, "suspend")==0){
		currentPCB = findPCB(arguments);
		if(currentPCB != NULL)
		{
			if(currentPCB->state == 4 || currentPCB->state == 5)
				output("This PCB is already suspended", 1);
			else if(currentPCB->state == 2)
				currentPCB->state = 4;
			else
				currentPCB->state = 5;
		}
		return (1);
	}
	else {
		return 0;
	}
}

/** \brief This changes the status of the PCB to unsuspended.
 * suspendPCB takes a suspended ready or suspended blocked
 * PCB and changes its status to ready or blocked respectively.
 * This cannot be called on a ready or blocked PCB.
 * @param command string - the command issued by the user
 * @param arguments string - the arguments issued by the user
 * @return int - returns 0 if this is not the correct command otherwise 1
 */
int resumePCB(char *command, char *arguments)
{
	 pcb *currentPCB;
	if (strcmp(command, "resume")==0){
		currentPCB = findPCB(arguments);
		if(currentPCB != NULL)
		{
			if(currentPCB->state == 2 || currentPCB->state == 3)
				output("This PCB is already unsuspended\n", 1);
			else if(currentPCB->state == 4)
				currentPCB->state = 2;
			else
				currentPCB->state = 3;//need to check how the state changes work, I believe that there are more conditions that must be checked.
		}
		return (1);
	}
	else {
		return 0;
	}
}

/**
 * \brief Deletes a PCB.
 * Deletes the process control block named in the arguments.
 * @param command string - the command issued by the user
 * @param arguments string - the arguments issued by the user
 * @return int - returns 0 if this is not the correct command otherwise 1
 */
int deletePCB(char* command, char* arguments) {
	if (strcmp(command, "delpcb")==0){
		pcb *temp; //Assign temporary PCB
		temp= findPCB(arguments); //Put pcb location in temp
		if (temp == NULL) {//If pcb name not found/doesn't exist
			output("PCB not found\n", 1);
		}//end if
		else{
			removePCB(arguments);
			freePCB(temp);
		}// end else
		return (1);
	}
	else{
		return 0;
	}

}//delete_PCB

/** \brief Allocates and sets up a new pcb and enters it into the ready queue.
 * Full description This function receives the valid process name, class and priority from the user.
 * This function also calls set_up pcb function to set up the pcb and calls insert_pcb to insert it into the ready queue.
 * @param command   This parameter stands for the command name the user will input in order to execute createPCB.
 * @param arguments This parameter stands for any arguments associated with the command that the user will input.
 * @return int - returns 1 if this is the correct command.
 * @deprecated This function was used for testing purposes in previous modules
 */
 /*
int createNewPCB(char* command, char* arguments) {
	int pcb_valid = 1;
	pcb *PCBPointer=NULL;
	char *temp = NULL;
	char name[20];
	int priority;
	int class;
	int i;

	if (strcmp(command, "newpcb")==0){
		temp = strtok(arguments, "-");
		strcpy(name, temp);
		temp = strtok(NULL, "-");
		if (strcmp(temp, "sys")==0){
			class = 1;
		} else if (strcmp(temp, "app")==0){
			class = 2;
		} else {
			class = 0;
		}
		temp = strtok(NULL, "-");
		priority = atoi(temp);
		for (i=0;i < strlen(name); i++){
			if (name[i]==' '){
				name[i]=0;
			}
		}
		PCBPointer = findPCB(name);
		if(PCBPointer == NULL) //check if already exists
	{
		if(class !=1 && class != 2) {
			pcb_valid = 0;
			output("The class selected is neither a system nor an application", 1);
		}//close if

		if(priority < -128 && priority > 127) {
			pcb_valid=0;
			output("The priority must be between -128 and 127", 1);
		}//end if

	}//close if
	else{
		pcb_valid = 0;
		output( "The PCB Name already exists.", 1);
	}
	if (pcb_valid==1) {
		PCBPointer= setupPCB(name, priority, class);
		insertPCB(PCBPointer);
	}//end if
	return (1);
	}// if new pcb
	else {
		return 0;
	}
}//end create_pcb function
*/

/**
 * \brief Changes the priority of a PCB.
 * Sets the priority of the named process control block to the input priority.
 * @param command string - the command issued by the user
 * @param arguments string - the arguments issued by the user
 * @return int - returns 0 if this is not the correct command otherwise 1
 */
int setPriority(char* command, char* arguments)
{
	 pcb *currentPCB;
	 char PCBname[15];
	 int priority, pos;
	if (strcmp(command, "setpriority")==0){
		for (pos = 0; pos < strlen(arguments); pos++){
			if (arguments[pos]==' '){
				break;
			}
		}
		strncpy(PCBname, arguments, pos);
		PCBname[pos] = 0;
		arguments = (arguments + pos);
		while (arguments[0]==' '){
			arguments = (arguments + 1);
		}
		priority = atoi(arguments);
		currentPCB = findPCB(PCBname);
		if(currentPCB != NULL)
		{
			currentPCB->priority = priority;
			if(currentPCB->state == 2 || currentPCB->state == 4)
			{
				removePCB(PCBname);
				insertPCB(currentPCB);
			}
		}
		return (1);
	}
	else {
		return 0;
	}
}


/**
 * \brief Prints out information for PCB's.
 * Prints out the information for a PCB or a list of PCB's.
 * @param command string - the command issued by the user
 * @param arguments string - the arguments issued by the user
 * @return int - returns 0 if this is not the correct command otherwise 1
 */
int print(char *command, char *argument)
{
	pcb *currentPCB = NULL;
	char temp[60];
	if(strcmp(command, "show")==0)
	{
		sprintf(temp, "%-12s%-13s%-10s%-19s\n", "Name", "Class", "Priority", "State");
		output(temp, 1);
		if(strcmp(argument, "ready")==0)
		{
			currentPCB = ready.first;
			while(currentPCB != NULL)
			{
				printSingle(currentPCB);
				currentPCB = currentPCB->next;
			}
		}
		else if(strcmp(argument, "blocked")==0)
		{
			currentPCB = blocked.first;
			while(currentPCB != NULL)
			{
				printSingle(currentPCB);
				currentPCB = currentPCB->next;
			}
		}
		else if(strcmp(argument, "all")==0)
		{
			currentPCB = ready.first;
			while(currentPCB != NULL)
			{
				printSingle(currentPCB);
				currentPCB = currentPCB->next;
			}

			currentPCB = blocked.first;
			while(currentPCB != NULL)
			{
				printSingle(currentPCB);
				currentPCB = currentPCB->next;
			}
		}
		else
		{
			currentPCB = findPCB(argument);
			if (currentPCB != NULL){
				printSingle(currentPCB);
			}
			else {
			}
		}
		return(1);
	}
	else{
		return 0;
	}
}


/**
 * \brief prints information for a single PCB.
 * @param currentPCB pcb - the PCB to print.
 */
void printSingle(pcb *currentPCB)
{
	 char tempOutput[200];
	 char state[30];
	 char class[30];
	if(currentPCB->state == RUNNING){
		strcpy(state, "Running");
	}
	else if(currentPCB->state == READY){
		strcpy(state, "Ready");
	}
	else if(currentPCB->state == BLOCKED){
		strcpy(state, "Blocked");
	}
	else if(currentPCB->state == SUSPENDED_READY){
		strcpy(state, "Suspended Ready");
	}
	else {
		strcpy(state, "Suspended Blocked");
	}
	if(currentPCB->processClass == SYSTEM){
		strcpy(class, "System");
	}
	else{
		strcpy(class, "Application");
	}
	sprintf(tempOutput, "%-12s%-13s%-10d%-19s\n", currentPCB->name, class, currentPCB->priority, state);
	output(tempOutput, 0);
}


/** \brief Loads programs for R3 by using pointers to functions in the provided file.
 * @param command string - the command issued by the user
 * @param arguments string - the arguments issued by the user
 * @return int - returns 0 if this is not the correct command otherwise 1
 * @deprecated Only used for Module R3
 */
 /*
int r3loader(char *command, char *argument){
	pcb *temppcb;
	if (strcmp(command, "loadr3")==0){
		temppcb = setupPCB("test1", 0, APPLICATION, 1, 0);
		temppcb->state = READY;
		setStack(temppcb, test1_R3);
		insertPCB(temppcb);
		temppcb = setupPCB("test2", 0, APPLICATION, 1, 0);
		temppcb->state = READY;
		setStack(temppcb, test2_R3);
		insertPCB(temppcb);
		temppcb = setupPCB("test3", 0, APPLICATION, 1, 0);
		temppcb->state = READY;
		setStack(temppcb, test3_R3);
		insertPCB(temppcb);
		temppcb = setupPCB("test4", 0, APPLICATION, 1, 0);
		temppcb->state = READY;
		setStack(temppcb, test4_R3);
		insertPCB(temppcb);
		temppcb = setupPCB("test5", 0, APPLICATION, 1, 0);
		temppcb->state = READY;
		setStack(temppcb, test5_R3);
		insertPCB(temppcb);
		return 1;
	}
	else {
		return 0;
	}
 }*/

/** \brief Sets parameters in the stack for processes in R3
 * @param temp pcb - the pcb to set_up
 * @param process void - pointer to the function acting as a process
 * @deprecated Only used for Module R3
 */
void setStack(pcb *temp, void (*process)()){
	context *npc;
	temp->stackTop = temp->stackTop - sizeof(context);
	npc = (context*) temp->stackTop;
	npc->IP = FP_OFF(process);
	npc->CS = FP_SEG(process);
	npc->FLAGS = 0x200;
	npc->DS = _DS;
	npc->ES = _ES;
}

/** \brief Launches the dispatcher for R3.
 * @param command string - the command issued by the user
 * @param arguments string - the arguments issued by the user
 * @return int - returns 0 if this is not the correct command otherwise 1
 * @deprecated Only used for Module R3
 */
int r3dispatch(char *command, char *argument){
	if(strcmp(command, "dispatch")==0){
		dispatch();
		return 1;
	}
	else{
		return 0;
	}
}

/** \brief Loads a program which exists outside of the operating system.
 * @param command string - the command issued by the user
 * @param arguments string - the arguments issued by the user
 * @return int - returns 0 if this is not the correct command otherwise 1
 */
int r4loader(char *command, char *argument){
	int rc;
	pcb *newpcb;
	char delim[] = " ";
	context *cont;
	int prog_len_p;
	int start_offset_p;
	char *tmp;
	char temp[20];
	char name[20];
	int priority, i;
	for (i = 0; i < 20; i++){
		name[i] = 0;
		temp[i] = 0;
	}
	if(strcmp(command, "load")==0){
		tmp = strtok(argument, delim);
		strcpy(name, tmp);
		tmp = strtok(NULL, delim);
		if (tmp == NULL){
			priority = 0;
		}
		else {
			strcpy(temp, tmp);
			for (i = 0; i < 20; i++){
				if ((temp[i] < 48 || temp[i] > 57) && temp[i] != 0){
					output("Invalid priority, defaulting to zero.\n",1);
					priority = 0;
					break;
				}
				else if (i == 19){
					priority = atoi(temp);
				}
			}
		}
		if(!findPCB(name)){
			context *npc;
			sys_check_program("\0", name, &prog_len_p, &start_offset_p);
			if (prog_len_p == 0){
				output("Invalid program.\n", 1);
				return 1;
			}
			newpcb = setupPCB(name, priority, APPLICATION, prog_len_p, start_offset_p, SYS_STACK_SIZE);
			rc =sys_load_program(newpcb->loadAddress, prog_len_p, "", name);
			if (rc<0){
				output("File does not exist.\n",1);
				return 1;
			}
			newpcb->stackTop = newpcb->stackTop - sizeof(context);
			npc = newpcb->stackTop;
			npc->IP = FP_OFF(newpcb->execAddress);
			npc->CS = FP_SEG(newpcb->execAddress);
			npc->FLAGS = 0x200;
			npc->DS = _DS;
			npc->ES = _ES;
			insertPCB(newpcb);
		}
		return 1;
	}
	else {
		return 0;
	}
}


/** \brief Terminates a process.
 * Removes a process from the running or blocked queue and frees the associated memory.
 * @param command string - the command issued by the user
 * @param arguments string - the arguments issued by the user
 * @return int - returns 0 if this is not the correct command otherwise 1
 */
int T800(char *command, char *argument){
	pcb *block;
	if (strcmp(command, "terminate")==0){
		block = findPCB(argument);
		if (block == NULL){
			output("PCB does not exist.\n",1);
		}
		else {
			if (block->processClass != SYSTEM){
				removePCB(argument);
				freePCB(block);
			}
			else {
				output("Cannot terminate a system process.\n",1);
			}
		}
		return 1;
	}
	else {
		return 0;
	}
}

/** \brief Kills all running processes with the exception of the command handler.
 * Indiscriminately removes all processes from a queue and frees their associated memory,
 * with the exception of the command handler. This is done recursively terminating the last
 * item in the queue first and the first last.
 * @param a pcb - the first pcb in the queue to be emptied
 */
void T1000(pcb *a){
	if (a->next != NULL){
		T1000(a->next);
	}
	freePCB(a);
}